package storage

import (
	"context"
	"encoding/json"
	"fmt"
	"strconv"
	"sync"
	"time"

	"enzyme-backend/core/models"
	"enzyme-backend/core/utils"

	"github.com/redis/go-redis/v9"
)

// RedisStorage Redis存储实现
type RedisStorage struct {
	client *redis.Client
}

type RedisMap struct {
	client *redis.Client
}

// GlobalRedis 全局Redis存储实例
var (
	GlobalRedis *RedisStorage
	redisOnce   sync.Once
)

// RedisConfig Redis配置
type RedisConfig struct {
	Host     string
	Port     int
	Password string
	DB       int
}

func init() {
	redisOnce.Do(func() {
		// 从环境变量读取Redis配置
		config := &RedisConfig{
			Host:     utils.ENV.REDIS_HOST,
			Password: utils.ENV.REDIS_PASSWORD,
			DB:       0,
		}

		if portStr := utils.GetEnv("REDIS_PORT", "6379"); portStr != "" {
			if port, err := strconv.Atoi(portStr); err == nil {
				config.Port = port
			} else {
				config.Port = 6379
				utils.GlobalLogger.Warning("环境变量REDIS_PORT格式错误，使用默认值: %d", config.Port)
			}
		} else {
			config.Port = 6379
			utils.GlobalLogger.Warning("环境变量REDIS_PORT未设置，使用默认值: %d", config.Port)
		}

		if dbStr := utils.GetEnv("REDIS_DB", "0"); dbStr != "" {
			if db, err := strconv.Atoi(dbStr); err == nil {
				config.DB = db
			} else {
				utils.GlobalLogger.Warning("环境变量REDIS_DB格式错误，使用默认值: %d", config.DB)
			}
		} else {
			utils.GlobalLogger.Warning("环境变量REDIS_DB未设置，使用默认值: %d", config.DB)
		}

		// 创建Redis客户端
		client := redis.NewClient(&redis.Options{
			Addr:     fmt.Sprintf("%s:%d", config.Host, config.Port),
			Password: config.Password,
			DB:       config.DB,
		})

		// 测试连接
		if err := client.Ping(context.Background()).Err(); err != nil {
			utils.GlobalLogger.Error("Redis连接失败: %v", err)
			return
		}

		GlobalRedis = &RedisStorage{
			client: client,
		}
		utils.GlobalLogger.Info("Redis存储已初始化")
	})
}

// GetClient 获取Redis客户端
func (rs *RedisStorage) GetClient() *redis.Client {
	return rs.client
}

// Close 关闭Redis连接
func (rs *RedisStorage) Close() error {
	if rs.client != nil {
		return rs.client.Close()
	}
	return nil
}

// ==================== Redis Map存储器实现 ====================

// Set 设置键值对
func (rm *RedisMap) Set(ctx context.Context, key string, value interface{}, expiration time.Duration) error {
	valueBytes, err := json.Marshal(value)
	if err != nil {
		return fmt.Errorf("序列化值失败: %w", err)
	}

	if expiration > 0 {
		return rm.client.Set(ctx, key, valueBytes, expiration).Err()
	}
	return rm.client.Set(ctx, key, valueBytes, 0).Err()
}

// Get 获取值
func (rm *RedisMap) Get(ctx context.Context, key string, dest interface{}) error {
	result, err := rm.client.Get(ctx, key).Result()
	if err != nil {
		if err == redis.Nil {
			return fmt.Errorf("键不存在: %s", key)
		}
		return fmt.Errorf("获取值失败: %w", err)
	}

	return json.Unmarshal([]byte(result), dest)
}

// Delete 删除键
func (rm *RedisMap) Delete(ctx context.Context, key string) error {
	return rm.client.Del(ctx, key).Err()
}

// Exists 检查键是否存在
func (rm *RedisMap) Exists(ctx context.Context, key string) (bool, error) {
	result, err := rm.client.Exists(ctx, key).Result()
	if err != nil {
		return false, fmt.Errorf("检查键存在失败: %w", err)
	}
	return result > 0, nil
}

// CreateRegisterTransaction 创建注册事务
func (rs *RedisStorage) CreateRegisterTransaction(ctx context.Context, email string, verifyCode string, expiredAt time.Time) error {
	transaction := &models.RegisterTransaction{
		Email:      email,
		VerifyCode: verifyCode,
		ExpiredAt:  expiredAt,
	}

	data, err := json.Marshal(transaction)
	if err != nil {
		return err
	}

	key := fmt.Sprintf("register_transaction:%s", email)
	duration := time.Until(expiredAt)

	return rs.client.Set(ctx, key, string(data), duration).Err()
}

// GetRegisterTransaction 获取注册事务
func (rs *RedisStorage) GetRegisterTransaction(ctx context.Context, email string) (*models.RegisterTransaction, error) {
	key := fmt.Sprintf("register_transaction:%s", email)
	data, err := rs.client.Get(ctx, key).Result()
	if err != nil {
		if err == redis.Nil {
			return nil, nil
		}
		return nil, err
	}

	var transaction models.RegisterTransaction
	if err := json.Unmarshal([]byte(data), &transaction); err != nil {
		return nil, err
	}

	return &transaction, nil
}

// DeleteRegisterTransaction 删除注册事务
func (rs *RedisStorage) DeleteRegisterTransaction(ctx context.Context, email string) error {
	key := fmt.Sprintf("register_transaction:%s", email)
	return rs.client.Del(ctx, key).Err()
}

// CreateOrderTransaction 创建订单事务
func (rs *RedisStorage) CreateOrderTransaction(ctx context.Context, orderType models.OrderType, token string) error {
	transaction := &models.OrderTransaction{
		OutTradeNo: utils.GenerateHex(32),
		UserToken:  token,
		OrderType:  orderType.Name,
		Amount:     orderType.Price,
		Status:     "waiting",
		CreatedAt:  time.Now(),
		UpdatedAt:  time.Now(),
		ExpiredAt:  time.Now().Add(24 * time.Hour),
	}

	data, err := json.Marshal(transaction)
	if err != nil {
		return err
	}

	key := fmt.Sprintf("order_transaction:%s", token)
	return rs.client.Set(ctx, key, string(data), 24*time.Hour).Err() // 订单24小时过期
}

// GetOrderTransaction 获取订单事务
func (rs *RedisStorage) GetOrderTransaction(ctx context.Context, transaction *models.OrderTransaction, token string) error {
	key := fmt.Sprintf("order_transaction:%s", token)
	data, err := rs.client.Get(ctx, key).Result()
	if err != nil {
		if err == redis.Nil {
			return err
		}
		return err
	}

	if err := json.Unmarshal([]byte(data), transaction); err != nil {
		return err
	}

	return nil
}

// FinishOrderTransaction 完成订单事务
func (rs *RedisStorage) FinishOrderTransaction(ctx context.Context, token string) error {
	var transaction models.OrderTransaction
	err := rs.GetOrderTransaction(ctx, &transaction, token)
	if err != nil {
		return err
	}

	transaction.Status = "completed"
	transaction.UpdatedAt = time.Now()

	data, err := json.Marshal(transaction)
	if err != nil {
		return err
	}

	key := fmt.Sprintf("order_transaction:%s", token)
	return rs.client.Set(ctx, key, string(data), 24*time.Hour).Err()
}

// CancelOrderTransaction 取消订单事务
func (rs *RedisStorage) CancelOrderTransaction(ctx context.Context, token string) error {
	var transaction models.OrderTransaction
	err := rs.GetOrderTransaction(ctx, &transaction, token)
	if err != nil {
		return err
	}

	transaction.Status = "cancelled"
	transaction.UpdatedAt = time.Now()

	data, err := json.Marshal(transaction)
	if err != nil {
		return err
	}

	key := fmt.Sprintf("order_transaction:%s", token)
	return rs.client.Set(ctx, key, string(data), 24*time.Hour).Err()
}

// SetEmailCode 保存邮箱验证码，3分钟过期
func (rs *RedisStorage) SetEmailCode(ctx context.Context, email, code string) error {
	key := fmt.Sprintf("email_code:%s", email)
	return rs.client.Set(ctx, key, code, 3*time.Minute).Err()
}

// GetEmailCode 获取邮箱验证码
func (rs *RedisStorage) GetEmailCode(ctx context.Context, email string) (string, error) {
	key := fmt.Sprintf("email_code:%s", email)
	return rs.client.Get(ctx, key).Result()
}

// DelEmailCode 删除邮箱验证码
func (rs *RedisStorage) DelEmailCode(ctx context.Context, email string) error {
	key := fmt.Sprintf("email_code:%s", email)
	return rs.client.Del(ctx, key).Err()
}
